package com.common.exception;

import com.common.result.Result;
import lombok.extern.slf4j.Slf4j;
import org.springframework.dao.DuplicateKeyException;
import org.springframework.http.HttpStatus;
import org.springframework.http.converter.HttpMessageNotReadableException;
import org.springframework.transaction.CannotCreateTransactionException;
import org.springframework.validation.BindingResult;
import org.springframework.validation.FieldError;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.annotation.*;

import javax.validation.ConstraintViolation;
import javax.validation.ConstraintViolationException;
import java.util.Set;

import static com.common.exception.CustomExceptionType.*;


/**
 * @author zdh
 */
@RestControllerAdvice
@Slf4j
public class WebExceptionHandler {

    /**
     * 非法参数异常
     */
    @ResponseStatus(HttpStatus.BAD_REQUEST)
    @ExceptionHandler(IllegalArgumentException.class)
    public Result illegalArgumentException(IllegalArgumentException e) {
        log.error("错误类型为IllegalArgumentException : "+e);
        return Result.error(e.getMessage(),e.getMessage());
    }

    /**
     * JSR303方法数据校验异常
     */
    @ResponseStatus(HttpStatus.BAD_REQUEST)
    @ExceptionHandler(MethodArgumentNotValidException.class)
    public Result methodArgumentNotValidException(MethodArgumentNotValidException e) {
        BindingResult bindingResult = e.getBindingResult();

        StringBuilder stringBuilder = new StringBuilder();
        for (FieldError error : bindingResult.getFieldErrors()) {
            String field = error.getField();
            Object value = error.getRejectedValue();
            String msg = error.getDefaultMessage();
            String message = String.format("错误字段：%s，错误值：%s，原因：%s；", field, value, msg);
            stringBuilder.append(message).append("    ");
        }
        log.error("错误类型为MethodArgumentNotValidException : "+stringBuilder.toString());
        return Result.error(stringBuilder.toString(),PARAM_RESOLVE_ERROR);
    }

    /**
     * 校验异常
     */
    @ResponseStatus(HttpStatus.BAD_REQUEST)
    @ExceptionHandler(ConstraintViolationException.class)
    public Result constraintViolationException(ConstraintViolationException e){
        Set<ConstraintViolation<?>> violations = e.getConstraintViolations();
        StringBuilder res = new StringBuilder();
        for (ConstraintViolation<?> v : violations) {
            String errMsg = v.getPropertyPath() + v.getMessage() + ",但你的值是: " + v.getInvalidValue();
            res.append(" ").append(errMsg).append("   ");
        }
        return Result.error(res.toString(),ILLEGAL_ARGUMENT);
    }

    @ResponseStatus()
    @ExceptionHandler(Exception.class)
    public Result exception(Exception e) {
        log.error("错误类型为Exception : "+e);
        return Result.error(e.getMessage(),INTERNAL_SERVER_ERROR);
    }

    @ResponseStatus()
    @ExceptionHandler(CustomException.class)
    public Result customException(CustomException e) {
        log.error("错误类型为customException : "+e);
        return Result.error(e.getBackErrMsg(),e.getFrontErrMsg());
    }

    @ResponseStatus()
    @ExceptionHandler(CannotCreateTransactionException.class)
    public Result cannotCreateTransactionException(CannotCreateTransactionException e) {
        log.error("错误类型为CannotCreateTransactionException : "+e);
        return Result.error("数据库连接超时",INTERNAL_SERVER_ERROR);
    }

    /**
     * 唯一索引重复异常
     */
    @ResponseStatus()
    @ExceptionHandler(DuplicateKeyException.class)
    public Result duplicateKeyException(Exception e) {
        String[] split = e.getCause().getMessage().split("'");
        String err = "字段: " + split[1] + " 发生了" + ("PRIMARY".equals(split[3]) ? "主键重复" : "唯一键重复") + "的错误";
        log.error("错误类型为duplicateKeyException : {}",err);
        return Result.error(err,INTERNAL_SERVER_ERROR);
    }

    /**
     * 空指针异常
     */
    @ResponseStatus(HttpStatus.NOT_FOUND)
    @ExceptionHandler(NullPointerException.class)
    public Result nullPointerException(NullPointerException e) {
        log.error("错误类型为NullPointerException : ",e);
        return Result.error(e.getMessage(),NOT_FOUND);
    }

    /**
     * JSON序列化时,通过在对象的setter方法中完成数据校验,校验失败后抛出自定义异常
     */
    @ResponseStatus(HttpStatus.BAD_REQUEST)
    @ExceptionHandler(HttpMessageNotReadableException.class)
    public Result httpMessageNotReadableException(HttpMessageNotReadableException e){
        log.error("错误类型为httpMessageNotReadableException: ",e);
        Throwable cause = e.getCause().getCause();
        if(cause instanceof CustomException){
            CustomException customException = (CustomException)cause;
            return Result.error(customException.getBackErrMsg(),customException.getBackErrMsg());
        }
        return Result.error(e.getMessage(),INTERNAL_SERVER_ERROR);
    }
}
